package redis.clients.jedis;

import com.google.common.collect.Maps;
import com.yvan.platform.HttpUtils;
import redis.clients.util.ObjectSize;

import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.atomic.AtomicLong;

import com.yvan.metric.Histogram;
import com.yvan.metric.Consts;

/**
 * redis 调用状况统计
 * Created by luoyifan on 2018/7/21.
 */
public class RedisStat {
    private static final AtomicLong executeCount = new AtomicLong();
    private static final AtomicLong resBytes = new AtomicLong();
    private static final Map<String, AtomicLong> executeCountMap = new ConcurrentHashMap<>();
    private static long maxResBytes = 0L;
    private static long maxCost = 0L;
    private static String maxCostUri = "";
    private static final AtomicLong totalCost = new AtomicLong();
    private static volatile Histogram costHistogram = new Histogram(Consts.RDS_COST_HISTOGRAM);
    private static volatile Histogram resHistogram = new Histogram(Consts.RDS_RES_HISTOGRAM);

    public static void incExecuteCount(String command) {
        executeCount.incrementAndGet();
        executeCountMap.computeIfAbsent(command, v -> new AtomicLong()).incrementAndGet();
    }

    public static long getExecuteCount() {
        return executeCount.get();
    }

    public static void resetStat() {
        executeCount.set(0L);
        resBytes.set(0L);
        totalCost.set(0L);

        executeCountMap.clear();
        costHistogram.reset();
        resHistogram.reset();

        maxResBytes = 0L;
        maxCost = 0L;

        maxCostUri = "";
    }

    public static void record(long start, long end, String command, AtomicLong size) {
        long cost = end - start;
        costHistogram.record(cost);
        maxCost = Math.max(cost, maxCost);
        if (cost == maxCost) {
            if (HttpUtils.currentRequest() != null) {
                maxCostUri = HttpUtils.currentRequest().getRequestURI();
            }
        }
        final long v = size.get();
        maxResBytes = Math.max(v, maxResBytes);
        resHistogram.record(v);
        resBytes.addAndGet(v);
        totalCost.addAndGet(cost);
    }

    public static void record(long start, long end, String command, Object res) {
        record(start, end, command, new AtomicLong(ObjectSize.sizeOf(res)));
    }

    public static Map<String, Long> methodCount() {
        Map<String, Long> r = Maps.newLinkedHashMap();
        for (Map.Entry<String, AtomicLong> entry : executeCountMap.entrySet()) {
            r.put(entry.getKey(), entry.getValue().get());
        }
        return r;
    }

    public static long[] getExecuteHistogram() {
        return costHistogram.toArray();
    }

    public static long[] getResSizeHistogram() {
        return resHistogram.toArray();
    }

    public static long getMaxResBytes() {
        return maxResBytes;
    }

    public static long getMaxCost() {
        return maxCost;
    }

    public static String getMaxCostUri() {
        return maxCostUri;
    }

    public static long getTotalCost() {
        return totalCost.get();
    }

    public static long getResBytes() {
        return resBytes.get();
    }
}
